/*
 * NOutputGateDescription.java
 * 
 * last update: 16.01.2010 by Stefan Saru
 * 
 * author:	Alec(panovici@elcom.pub.ro)
 * 
 * Obs:
 */
package engine;

import java.util.*;
import java.io.*;
import middle.*;

/**
 * n_output_gate can be one of the following:
 * buf/not
 */

class NOutputGateDescription extends StdGateDescription
{

	NOutputGateDescription (byte type) {
		super(type, 2);
	}

	///////////////////////////////
	// ModuleFactory implementation
	///////////////////////////////


	public Object createNewModule(NameSpace parent,
			ModuleInstanceDescription miDesc,
			byte strength,
			ScopeNode scope)
	throws ParseException
	{
		xConsole.debug("creating new NInputGate");
		SelectionExpressionDescription outputs =
			new SelectionExpressionDescription();
		ExpressionDescription input;
		Enumeration e = miDesc.portsVector.elements();
		portloop:
			while(true) {
				ExpressionDescription ck = (ExpressionDescription)e.nextElement();
				if (!e.hasMoreElements()) {
					input = ck != null ? (ExpressionDescription) ck :
						ConstantDescription.zDescription; //the last port is the input
					break portloop;
				}
				if (ck != null)
					outputs.addChunk(ck);
			}

		try {
			((AssignableSelection)outputs).toContSelection(strength);
		} catch (ClassCastException cex) {
			throw new ParseException (parent.desc.toString(miDesc.lineNo) +
					": error: output expressions are not a net selections or concatenations");
		}

		return new NOutputGate (parent, delay,
				(LeftValue) outputs.instantiate(parent),
				input.instantiate(parent), miDesc, type);
	}

	public Object createNewModuleArray(NameSpace parent,
			ModuleInstanceDescription miDesc,
			byte strength,
			ScopeNode scope, int ars, int are,
			int n, int increment)
	throws ParseException
	{

		Enumeration en = miDesc.portsVector.elements();
		NOutputGate gates[] = new NOutputGate[n];
		Vector[] outputs = new Vector[n];
		for (int i = 0; i < n; i++)
			outputs[i] = new Vector();
		Expression[] inputs = new Expression[n];
		Monitor m;

		portloop:
			while(true) {
				ExpressionDescription ed =
					(ExpressionDescription) en.nextElement();
				if (!en.hasMoreElements()) { //ed should be the input port
					Expression in;
					in =
						ed == null ? ConstantDescription.zDescription.instantiate(parent) :
							ed.instantiate(parent);
						if (in.length != 1) {
							if (in.length != n)
								throw new ParseException(parent.desc.toString(miDesc.lineNo) +
										": error: bad input port length");
							BitVector buffer = new BitVector(in.length-1, 0, false);
							for (int j = 0; j < n; j++)
								inputs[j] = new BitSelect(parent, buffer, null, j, j);
							m = new LinkMonitor(new BitSelect(parent, buffer,
									null, n-1, 0),
									in);
						} else
							for (int j = 0; j < n; j++)
								inputs[j] = in;
						break portloop;
				}

				if ( ed == null) continue; //unassigned output
				try {
					((AssignableSelection) ed).toContSelection(strength);
				} catch (ClassCastException cex) {
					throw new ParseException(parent.desc.toString(miDesc.lineNo) +
							": error: bad output port expression: \"" +
							ed + "\" : not a net");
				}

				LeftValue out;
				try {
					out = (LeftValue) ed.instantiate(parent);
				} catch (ClassCastException cex) {
					throw new ParseException (parent.desc.toString(miDesc.lineNo) +
							": error: bad output port expression: \"" +
							ed + "\"not a lValue");
				}

				if (out.length() != 1) {
					if (out.length() != n)
						throw new ParseException(parent.desc.toString(miDesc.lineNo) +
								": error: bad output port" +
								" expression length for \"" +
								ed + "\"");
					BitVector buffer = new BitVector(n-1, 0, false);
					m = new LinkMonitor(out, new BitSelect(parent, buffer,
							null, n-1, 0));
					for (int i = 0; i < n; i++)
						outputs[i].addElement(new BitSelect(parent, buffer, null, i, i));
				} else {
					outputs[1].addElement((LeftValue) out);
					for (int i = 1; i < n; i++)
						outputs[i].addElement((LeftValue) ed.instantiate(parent));
				}
			}

		for (int i = 0; i < n; i++)
			gates [i] = new NOutputGate(parent, delay,
					new SelectionExpression(parent,
							outputs[i],
							-31415),
							inputs[i], miDesc, type);
		return gates;
	}
}

